<template>
  <div class="upload-box">
    <a-upload
      :multiple="multiple"
      :disabled="disabled"
      class="upload"
      :class="{'hide': fileList.length >= limitNum}"
      name="file"
      list-type="picture-card"
      accept=".jpg,jpeg,.png"
      :fileList="fileList"
      :customRequest="fileUpload"
      :remove="fileRemove"
      @preview="filePriview">
      <div class="flex-v">
        <a-icon :type="loading ? 'loading' : 'plus'" class="upload__icon"/>
        <span>点击上传</span>
      </div>
    </a-upload>
    <Preview
      v-if="previewShow"
      :url-list="previewList"
      :onClose="closePreview"
    />
  </div>
</template>

<script>
import { uploadFileAPI } from '@/api/file'
import Preview from '@/components/Image/code/preview.vue'
import { formatUrl } from '@/utils/util'

let bodyOverflow = ''
export default {
  components: { Preview },
  props: {
    value: {
      type: Array,
      default: () => []
    },
    type: {
      type: String,
      default: ''
    },
    limitNum: {
      type: Number,
      default: 9
    },
    limitNumText: {
      type: String,
      default: '文件数量已达上限'
    },
    limitSize: {
      type: Number,
      default: 1024 * 1024 * 30 // 30M
    },
    limitSizeText: {
      type: String,
      default: '文件大小不得超过30M'
    },
    disabled: {
      type: Boolean,
      default: false
    },
    multiple: {
      type: Boolean,
      default: false
    },
    isWaterMarker: {
      type: Boolean,
      default: false
    },
    waterMarker: {
      type: Object,
      default: () => {}
    },
    showList: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      loading: false,
      fileList: [],
      previewShow: false,
      previewList: []
    }
  },
  watch: {
    value: {
      handler: function () {
        this.showList && this.fileListAPI()
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    // 上传图片
    async fileUpload (e) {
      if (this.fileList.length >= this.limitNum) return this.$message.error(this.limitNumText)
      const file = e.file
      if (file.size > this.limitSize) return this.$message.error(this.limitSizeText)
      const fileFormData = new FormData()
      // fileFormData.append('type', this.type)
      this.fileList.push({
        uid: file.uid,
        name: file.name,
        status: 'uploading',
        url: '',
        finalUrl: ''
      })
      // 添加水印
      if (this.isWaterMarker) {
        const newFile = await this.addWaterMarker(file)
        fileFormData.append('file', newFile)
      } else {
        fileFormData.append('file', file)
      }

      this.fileLoading = true
      uploadFileAPI(fileFormData, 'place').then(res => {
        const path = res.data.path || ''
        const target = this.fileList.find(item => item.uid === file.uid)
        target.status = 'done'
        target.url = formatUrl(path)
        target.finalUrl = path
        this.syncFileId()
      }).catch(() => {
        const index = this.fileList.findIndex(item => item.uid === file.uid)
        this.fileList.splice(index, 1)
      }).finally(() => {
        this.fileLoading = false
      })
    },
    // 添加水印
    addWaterMarker (file) {
      return new Promise((resolve) => {
        const name = this.waterMarker.name
        const date = this.waterMarker.date
        const height = 120
        const width = 200
        const fontSize = 14
        const img = new Image()
        img.src = window.URL.createObjectURL(file)
        img.onload = () => {
          const canvas = document.createElement('canvas')
          const imgWidth = img.width
          const imgHeight = img.height
          canvas.width = imgWidth
          canvas.height = imgHeight
          const ctx = canvas.getContext('2d')
          ctx.drawImage(img, 0, 0, imgWidth, imgHeight)
          ctx.textAlign = 'left'
          ctx.textBaseline = 'top'
          ctx.font = `${fontSize}px Microsoft Yahei`
          ctx.fillStyle = 'rgba(255, 255, 255,0.25)'

          ctx.rotate(-20 * Math.PI / 180)
          let i = 0
          let j = 0
          const waterMarkerWidth = name.split('').length * fontSize

          for (i = 0; i <= imgWidth / (waterMarkerWidth) + 100; i++) {
            for (j = 0; j <= imgHeight / (height - 20) + 100; j++) {
              const x = i * (waterMarkerWidth + width) - 100

              if (j === 0) {
                ctx.fillText(name, x, -height, imgWidth)
                ctx.fillText(date, x, -height + 20, imgWidth)
              }
              ctx.fillText(name, x, j * height, imgWidth)
              ctx.fillText(date, x, j * height + 20, imgWidth)
            }
          }

          const dataURLtoBlob = (dataurl, name) => {
            const arr = dataurl.split(',')
            const mime = arr[0].match(/:(.*?);/)[1]
            const bstr = atob(arr[1])
            let n = bstr.length
            const u8arr = new Uint8Array(n)
            while (n--) {
              u8arr[n] = bstr.charCodeAt(n)
            }
            return new File([u8arr], name, {
              type: mime
            })
          }
          const base64 = canvas.toDataURL('image/jpeg', 0.8)
          const newFile = dataURLtoBlob(base64, file.name)
          resolve(newFile)
        }
      })
    },
    // 附件删除
    fileRemove (file) {
      if (file.status === 'uploading') return false
      const index = this.fileList.findIndex(item => item.uid === file.uid)
      if (index === -1) return false
      this.fileList.splice(index, 1)
      this.syncFileId()
      return true
    },
    // 获取图片列表
    fileListAPI () {
      this.loading = true
      const files = []
      this.value.forEach(url => {
        files.push({
          uid: url,
          name: url,
          status: 'done',
          url: formatUrl(url),
          finalUrl: url
        })
      })
      this.fileList = files
      this.loading = false
    },
    // 预览
    filePriview (file) {
      this.previewList = [file.url]
      if (this.previewShow) return
      bodyOverflow = document.body.style.overflow
      document.body.style.overflow = 'hidden'
      this.previewShow = true
    },
    // 关闭预览
    closePreview () {
      document.body.style.overflow = bodyOverflow
      this.previewShow = false
    },
    // 同步fileId
    syncFileId () {
      this.$emit('input', this.fileList.map(item => item.finalUrl))
    }
  }
}
</script>

<style lang="less" scoped>
.upload-box {
  line-height: 0;
  /deep/ .hide {
    .ant-upload-select{
      display: none;
    }
  }
}
.upload{
  text-align: center;
}
.upload__icon{
  font-size: 20px;
  margin-bottom: 10px;
}
</style>
